/* Copyright (C) 2011 rccloud.com All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.rccloud.gwtproxyc.server;

import java.util.ArrayList;
import java.util.List;

/**
 * Proxy class is used to convert between entity object and GWT object
 * 
 * e.g.
 * 
 * <pre>
 * UserProxy proxy = Proxy.createProxy(UserProxy.class, userObject);
 * User user = Proxy.fromProxy(User.class, proxy);
 * </pre>
 */
public class Proxy {

	/**
	 * Create GWT proxy object from entity objects
	 * 
	 * @param <T>
	 *            GWT object class type
	 * 
	 * @param proxyClass
	 *            GWT object class type info
	 * 
	 * @param sources
	 *            entity objects need to be converted
	 * 
	 * @return GWT object
	 */
	public static <T> T createProxy(Class<T> proxyClass, Object... sources) {
		try {
			T target = (T) proxyClass.newInstance();
			for (Object source : sources) {
				if (source != null)
					recreateProxy(proxyClass, target, source);
			}
			return target;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * Batch create GWT proxy objects
	 * 
	 * @param <T>
	 *            GWT object class type
	 * 
	 * @param <V>
	 *            entity object class type
	 * 
	 * @param proxyClass
	 *            GWT object class type info
	 * 
	 * @param sources
	 *            entity objects need to be converted
	 * 
	 * @return GWT objects
	 */
	public static <T, V> List<T> createProxyList(Class<T> proxyClass,
			List<V> sources) {
		if (sources == null)
			return new ArrayList<T>();
		List<T> ts = new ArrayList<T>();
		for (Object source : sources)
			if (source != null)
				ts.add(createProxy(proxyClass, source));
		return ts;
	}

	/**
	 * Create new GWT object from existing GWT object and entity object
	 * 
	 * @param <T>
	 *            GWT object class type
	 * 
	 * @param proxyClass
	 *            GWT object class type info
	 * 
	 * @param target
	 *            existing GWT object
	 * 
	 * @param source
	 *            entity object
	 * 
	 */
	public static <T> void recreateProxy(Class<T> proxyClass, T target,
			Object source) {
		if (source == null)
			return;
		try {
			// Get method info
			ProxyResolver resolver = ProxyResolverFactory
					.getResolver(proxyClass);
			List<MethodProxyInfo> setMethodList = resolver
					.resolveMethodProxyInfo();

			for (MethodProxyInfo setMethodInfo : setMethodList) {

				if (setMethodInfo.getTargetClass().equals(source.getClass())) {

					// Set value for target
					Object value = setMethodInfo.getTargetGetMethod().invoke(
							source);
					Object newvalue = setMethodInfo
							.getConverter()
							.newInstance()
							.convertToProxy(
									setMethodInfo.getProxyField().getClass(),
									value);
					setMethodInfo.getSetMethod().invoke(target, newvalue);
				}
			}

		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	/**
	 * Create entity object from GWT objects
	 * 
	 * @param <T>
	 *            entity class type
	 * 
	 * @param entityClass
	 *            entity class type info
	 * 
	 * @param proxyObjects
	 *            GWT objects need to be converted
	 * 
	 * @return entity object
	 */
	public static <T> T fromProxy(Class<T> entityClass, Object... proxyObjects) {
		try {
			T entity = (T) entityClass.newInstance();
			for (Object proxy : proxyObjects) {
				if (proxy != null)
					refromProxy(entityClass, entity, proxy);
			}
			return entity;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * Create new entity object from existing entity object and GWT object
	 * 
	 * @param <T>
	 *            entity class type
	 * 
	 * @param entityClass
	 *            entity class type info
	 * 
	 * @param entity
	 *            existing entity object
	 * 
	 * @param proxyObject
	 *            GWT object
	 * 
	 */
	public static <T> void refromProxy(Class<T> entityClass, Object entity,
			Object proxyObject) {
		if (proxyObject == null)
			return;
		try {
			// Get method info
			Class<?> proxyClass = proxyObject.getClass();
			ProxyResolver resolver = ProxyResolverFactory
					.getResolver(proxyClass);
			List<MethodProxyInfo> setMethodList = resolver
					.resolveMethodProxyInfo();

			for (MethodProxyInfo setMethodInfo : setMethodList) {

				if (setMethodInfo.getTargetClass().equals(entityClass)) {

					// Set value for target
					Object value = setMethodInfo.getGetMethod().invoke(
							proxyObject);
					Object newvalue = setMethodInfo.getConverter()
							.newInstance().convertFromProxy(value);
					setMethodInfo.getTargetSetMethod().invoke(entity, newvalue);
				}
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
}
